package com.billion.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.billion.payment.config.AlipayConfig;
import com.billion.payment.entity.ali.AliOrderEntity;
import com.billion.payment.entity.ali.AliPayEntity;
import com.billion.payment.entity.ali.AliRefundEntity;
import com.billion.payment.service.IAlipayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * @author 王琦
 * @date 2021/12/16
 */
@Slf4j
@Service
public class AlipayServiceImpl implements IAlipayService {

    /**
     * 构建支付参数
     * @param appid
     * @param privateKey
     */
    private AlipayClient createClient(String appid, String privateKey, String publicKey){
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.GATEWAY_URL, appid, privateKey, AlipayConfig.FORMAT, AlipayConfig.CHARSET, publicKey, AlipayConfig.SIGN_TYPE);
        return alipayClient;
    }

    /**
     * 支付宝统一下单
     * @param aliOrderEntity
     * @return
     */
    @Override
    public JSONObject order(AliOrderEntity aliOrderEntity) {
        JSONObject jsonObject = new JSONObject();

        AlipayClient alipayClient = createClient(aliOrderEntity.getAppId(), aliOrderEntity.getPrivateKey(), aliOrderEntity.getPublicKey());
        AlipayTradeCreateResponse createResponse = order(alipayClient, aliOrderEntity);
        if(createResponse.isSuccess()){
            String outTradeNo = createResponse.getOutTradeNo();
            String tradeNo = createResponse.getTradeNo();
            if(createResponse.getCode().equals("10000")){
                jsonObject.put("outTradeNo", outTradeNo);
                jsonObject.put("tradeNo", tradeNo);
                jsonObject.put("code", "success");
            }else{
                jsonObject.put("code", createResponse.getCode());
                jsonObject.put("msg", createResponse.getMsg());
            }
        }else{
            jsonObject.put("code", "fail");
            jsonObject.put("msg", "统一下单失败");
        }
        return jsonObject;
    }

    /**
     * 条码付款
     * @param aliOrderEntity
     * @return
     */
    private AlipayTradeCreateResponse order(AlipayClient alipayClient, AliOrderEntity aliOrderEntity){
        AlipayTradeCreateRequest createRequest = new AlipayTradeCreateRequest();
        AlipayTradeCreateModel createModel = new AlipayTradeCreateModel();
        //订单号
        createModel.setOutTradeNo(aliOrderEntity.getOutTradeNo());
        // 订单标题
        createModel.setSubject(aliOrderEntity.getSubject());
        //订单内容
        createModel.setBody(aliOrderEntity.getBody());
        //支付金额
        createModel.setTotalAmount(aliOrderEntity.getTotalAmount());
        //付款人员
        createModel.setBuyerId(aliOrderEntity.getBuyerId());
        //超时时间
        createModel.setTimeoutExpress(AlipayConfig.TIMEOUT_EXPRESS);
        createRequest.setBizModel(createModel);
        createRequest.setNotifyUrl(AlipayConfig.getNotifyUrl());
        AlipayTradeCreateResponse  createResponse = null;
        try {
            createResponse = alipayClient.execute(createRequest);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return createResponse;
    }

    /**
     * 阿里支付
     * @param aliPayEntity
     * @return
     */
    @Override
    public JSONObject pay(AliPayEntity aliPayEntity) {
        JSONObject jsonObject = new JSONObject();

        AlipayClient alipayClient = createClient(aliPayEntity.getAppId(), aliPayEntity.getPrivateKey(), aliPayEntity.getPublicKey());
        AlipayTradePayResponse payResponse = pay(alipayClient, aliPayEntity);
        if(payResponse.isSuccess()){
            String outTradeNo = payResponse.getOutTradeNo();
            String tradeNo = payResponse.getTradeNo();
            if(payResponse.getCode().equals("10000")){
                jsonObject.put("outTradeNo", outTradeNo);
                jsonObject.put("tradeNo", tradeNo);
                jsonObject.put("code", "success");
            }else if(payResponse.getCode().equals("10003")){
                boolean flag = true;
                int count = 0;
                while (flag){
                    try {
                        Thread.sleep(5000L);
                        AlipayTradeQueryResponse queryResponse = queryPay(alipayClient, tradeNo);
                        if(queryResponse.isSuccess() && queryResponse.getCode().equals("10000")){
                            jsonObject.put("outTradeNo", outTradeNo);
                            jsonObject.put("tradeNo", tradeNo);
                            jsonObject.put("code", "success");
                            flag = false;
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        flag = false;
                        jsonObject.put("code", "fail");
                        jsonObject.put("msg", e.getCause());
                    } finally {
                        count ++;
                        if(count > 20){
                            cancelPay(alipayClient, tradeNo);
                            flag = false;
                            jsonObject.put("code", "fail");
                            jsonObject.put("msg", "订单超时，订单已关闭");
                        }
                    }

                }
            }
        }else{
            jsonObject.put("code", "fail");
            jsonObject.put("msg", "支付失败");
        }
        return jsonObject;
    }

    /**
     * 条码付款
     * @param aliPayEntity
     * @return
     */
    private AlipayTradePayResponse pay(AlipayClient alipayClient, AliPayEntity aliPayEntity){
        AlipayTradePayRequest payRequest = new AlipayTradePayRequest();
        AlipayTradePayModel payModel = new AlipayTradePayModel();
        //订单号
        payModel.setOutTradeNo(aliPayEntity.getOutTradeNo());
        // 支付授权码
        payModel.setAuthCode(aliPayEntity.getAuthCode().trim());
        // 订单标题
        payModel.setSubject(aliPayEntity.getSubject());
        // 订单描述信息
        payModel.setBody(aliPayEntity.getBody());
        //支付金额
        payModel.setTotalAmount(aliPayEntity.getTotalAmount());
        //超时时间
        payModel.setTimeoutExpress(AlipayConfig.TIMEOUT_EXPRESS);
        payRequest.setBizModel(payModel);
        AlipayTradePayResponse  payResponse = null;
        try {
            payResponse = alipayClient.execute(payRequest);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return payResponse;
    }

    /**
     * 轮询查询交易结果
     * @param tradeNo
     * @return
     */
    private AlipayTradeQueryResponse queryPay(AlipayClient alipayClient, String tradeNo){
        AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
        queryModel.setTradeNo(tradeNo);
        queryRequest.setBizModel(queryModel);
        AlipayTradeQueryResponse queryResponse = null;
        try {
            queryResponse = alipayClient.execute(queryRequest);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return queryResponse;
    }

    /**
     * 取消订单
     * @param tradeNo
     * @return
     */
    private void cancelPay(AlipayClient alipayClient, String tradeNo){
        AlipayTradeCancelRequest cancelRequest = new AlipayTradeCancelRequest();
        AlipayTradeCancelModel cancelModel = new AlipayTradeCancelModel();
        cancelModel.setTradeNo(tradeNo);
        cancelRequest.setBizModel(cancelModel);
        try{
            alipayClient.execute(cancelRequest);
        }catch (AlipayApiException e){
            e.printStackTrace();
        }
    }

    /**
     * 退费
     * @param aliRefundEntity
     * @return
     */
    @Override
    public JSONObject refund(AliRefundEntity aliRefundEntity) {
        JSONObject jsonObject = new JSONObject();

        AlipayClient alipayClient = createClient(aliRefundEntity.getAppId(), aliRefundEntity.getPrivateKey(), aliRefundEntity.getPublicKey());
        AlipayTradeRefundResponse refundResponse = this.refund(alipayClient, aliRefundEntity);
        if(refundResponse.isSuccess()){
            String outTradeNo = refundResponse.getOutTradeNo();
            String tradeNo = refundResponse.getTradeNo();
            if(refundResponse.getFundChange().equals("Y")){
                jsonObject.put("outTradeNo", outTradeNo);
                jsonObject.put("tradeNo", tradeNo);
                jsonObject.put("code", "success");
            }else{
                jsonObject.put("code", refundResponse.getCode());
                jsonObject.put("msg", refundResponse.getMsg());
            }
        }else{
            jsonObject.put("code", "fail");
            jsonObject.put("msg", "退费失败");
        }
        return jsonObject;
    }

    /**
     * 退费
     * @param alipayClient
     * @param aliRefundEntity
     * @return
     */
    private AlipayTradeRefundResponse refund(AlipayClient alipayClient, AliRefundEntity aliRefundEntity){
        AlipayTradeRefundRequest refundRequest = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
        //支付宝订单号
        refundModel.setTradeNo(aliRefundEntity.getTradeNo());
        // 退款金额
        refundModel.setRefundAmount(aliRefundEntity.getRefundAmount());
        //退款请求号
        refundModel.setOutRequestNo(aliRefundEntity.getOutTradeNo());
        refundRequest.setBizModel(refundModel);
        AlipayTradeRefundResponse refundResponse = null;
        try {
            refundResponse = alipayClient.execute(refundRequest);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return refundResponse;
    }

    /**
     * 获取支付宝openid
     * @param appId
     * @param privateKey
     * @param code
     * @return
     */
    @Override
    public String getOpenId(String appId, String privateKey, String publicKey, String code){
        String openId = "";
        try {
            AlipaySystemOauthTokenRequest oauthTokenRequest = new AlipaySystemOauthTokenRequest();
            oauthTokenRequest.setCode(code);
            oauthTokenRequest.setGrantType("authorization_code");
            AlipayClient alipayClient = this.createClient(appId, privateKey, publicKey);
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(oauthTokenRequest);
            openId = oauthTokenResponse.getUserId();
        }catch (Exception e){
            e.printStackTrace();
        }
        return openId;

    }
}
